/////////////////////////////////////////////////////////////////////////
//
// Amuse Engine SDK - system/ccm
// Copyright( c) 2014.  All Rights Reserved
//
// File:		AESubject.h
// Author:		Gianluca Belardelli
// Date:		26/06/2014
//
/////////////////////////////////////////////////////////////////////////
#ifndef _AESUBJECT_H_
#define _AESUBJECT_H_

class AESubject : public AESubjectI
{
// Members
public:
	static const AEUINT32 AEInvalidSubjectID = AEUINT32( -1 );

protected:

    /// <summary>
    ///   Defines a structure used by the subject to store information about observers
    ///   for PostChanges notifications (CCMs).
    /// </summary>
	struct AEObserverRequest
	{
		AEObserverRequest( AEObserverI *lpObserver = 0L,
					AEUINT32 uiInterests = 0,
					AEUINT32 uiMyID = 0	) : m_lpObserver( lpObserver ),
										m_uiInterestBits( uiInterests ),
										m_uiMyID( uiMyID )	{ }

		AEObserverI	*m_lpObserver;
		AEUINT32	m_uiInterestBits;
		AEUINT32	m_uiMyID;

		bool operator == ( AEObserverI *lpRhs ) const
		{
			return m_lpObserver == lpRhs;
		}
	};

private:
    // IMPLEMENTATION NOTE
    // Since only Change Control Managers (CCM) are supposed to subscribe for 
    // notifications sent by PostChange, there are not many observers expected 
    // to be in the list. Another assumption is that repeated attaches are infrequent.
    // Thus the most frequent operation is the traversal and thus the usual std::list
    // will suit fine here.
    typedef AETList<AEObserverRequest *> ObserverList;

    // List of the observers (CCMs) that need notifications about changes in this subject 
    ObserverList    m_lstObserverList;

#ifdef SUPPORT_CONCURRENT_ATTACH_DETACH_TO_SUBJECTS
    // Synchronization object to protect m_lstObserverList
    AECriticalSection	m_csObserverListMutex;
#endif

// Methods
private:
	friend AEUINT32 GetBitsToPost( AEObserverRequest &refRequest, AEUINT32 uiChangeMask );

public:
    AESubject( void );
    ~AESubject( void );

    virtual AEUINT32 Attach( AEObserverI *lpInObserver, AEUINT32 uiInIntrestBits, AEUINT32 uiID, AEUINT32 uiShiftBits = 0 );
    virtual AEUINT32 Detach( AEObserverI *lpInObserver );
    virtual AEUINT32 UpdateInterestBits( AEObserverI *lpInObserver, AEUINT32 uiInIntrestBitsMask );
    virtual AEUINT32 GetID ( AEObserverI *lpObserver ) const;
	virtual void PostChanges( AEUINT32 uiInChangedMask );
    virtual AEUINT32 GetPotentialSystemChangesMask( void );
    virtual void PreDestruct( void );
};

#endif // _AESUBJECT_H_
